#include <yatak/yatak.h>
#include <yatak/kheap.h>
#include <yatak/mutex.h>
#include <string.h>
#include <list.h>

void * add2List (list_t * head, void * item, size_t size)
{
	//uint32 flags;
	list_t * tmp;
	//save_flags (flags);
	//cli();
	static mutex_t mutex;
	mutex_enter(&mutex);
	if (head == NULL)
	{
		head = (list_t *)kmalloc (sizeof (list_t));
		head->size = size;
		if (size)
		{
			head->item = (void *)kmalloc (size);
			memcpy(head->item,item,size);
		}
		else
		{
			head->item = (void *)item;
		}
		head->next = NULL;
		mutex_leave(&mutex);
		//restore_flags (flags);
		return (void *) head;
	}
	tmp = head;
	while (tmp->next) tmp = tmp->next;
	tmp->next = (list_t *)kmalloc (sizeof (list_t));
	tmp->next->size = size;
	if (size)
	{
		tmp->next->item = (void *)kmalloc (size);
		memcpy(tmp->next->item,item,size);
	}
	else
	{
		tmp->next->item = (void *)item;
	}
	tmp->next->next = NULL;
	mutex_leave(&mutex);
	return (void *) head;
}

void * push2List (list_t * head, void * item, size_t size)
{
	//uint32 flags;
	//save_flags (flags);
	//cli();
	static mutex_t mutex;
	mutex_enter(&mutex);
	list_t * tmp = (list_t *)kmalloc (sizeof (list_t));
	tmp->size = size;
	if (size)
	{
		tmp->item = (void *)kmalloc (size);
		memcpy(tmp->item,item,size);
	}
	else
	{
		tmp->item = (void *)item;
	}
	tmp->next = head;
	mutex_leave(&mutex);
	//restore_flags (flags);
	return tmp;
}

void * get_list_item (list_t * head, size_t number)
{
	list_t * tmp = head;
	//uint32 flags;
	//save_flags (flags);
	//cli();
	static mutex_t mutex;
	mutex_enter(&mutex);
	while (0 < (number--) && tmp) tmp = tmp->next;
	mutex_leave(&mutex);
	//restore_flags (flags);
	if (!tmp || !number)
		return (void *) NULL;
	return (void *) tmp->item;
}

size_t get_list_item_s (list_t * head, size_t number)
{
	list_t * tmp = head;
	//uint32 flags;
	//save_flags (flags);
	//cli();
	static mutex_t mutex;
	mutex_enter(&mutex);
	while (0 < (number--) && tmp) tmp = tmp->next;
	mutex_leave(&mutex);
	//restore_flags (flags);
	if (!tmp || !number)
		return (size_t)NULL;
	return tmp->size;
}

void * pop_list (list_t * head)
{
	list_t *tmp = head;
	//uint32 flags;
	//save_flags (flags);
	//cli();
	static mutex_t mutex;
	mutex_enter(&mutex);
	if (!head)
	{
		mutex_leave(&mutex);
		//restore_flags (flags);
		return (void*)NULL;
	}
	head = head->next;
	void * t;
	if (!tmp->size)
		t = tmp->item;
	else
	{
		t = (void *)kmalloc (tmp->size);
		memcpy(t,tmp->item,tmp->size);
		kfree (tmp->item);
	}
	kfree (tmp);
	mutex_leave(&mutex);
	//restore_flags (flags);
	return (void *) t;
}

void * remove_list_item (list_t * head, size_t number)
{
	list_t * tmp = head;
	//uint32 flags;
	//save_flags (flags);
	//cli();
	static mutex_t mutex;
	mutex_enter(&mutex);
	while (0 < (number--) && tmp) tmp = tmp->next;
	if (!tmp || !number)
	{
		mutex_leave(&mutex);
		//restore_flags (flags);
		return (void *)1;
	}
	list_t * temp = head;
	if (tmp != head)
	{
		while (temp && temp->next != tmp) temp = temp->next;
		if (!temp)
		{
			mutex_leave(&mutex);
			//restore_flags (flags);
			return (void *)2;
		}
		temp->next = tmp->next;
	}
	else
	{
		head = head->next;
	}
	if (tmp->size)
		kfree (tmp->item);
	kfree (tmp);
	mutex_leave(&mutex);
	//restore_flags (flags);
	return (void *)0;
}
	
void * remove_list (list_t * head)
{
	static mutex_t mutex;
	mutex_enter(&mutex);
	while (!remove_list_item (head, (size_t)0));
	mutex_leave(&mutex);
	return (void *)0;
}

void * add2dList (dlist_t * head, void * item, size_t size)
{
	dlist_t * tmp = head;
	//uint32 flags;
	//save_flags (flags);
	//cli();
	static mutex_t mutex;
	mutex_enter(&mutex);
	if (tmp == NULL)
	{
		tmp = (dlist_t *)kmalloc (sizeof (dlist_t));
		tmp->size = size;
		if (size)
		{
			tmp->item = (void *)kmalloc (size);
			memcpy(tmp->item,item,size);
		}
		else
		{
			tmp->item = (void *)item;
		}
		tmp->next = NULL;
		tmp->back = NULL;
		mutex_leave(&mutex);
		//restore_flags (flags);
		return tmp;
	}
	while (tmp->next) tmp = tmp->next;
	tmp->next = (dlist_t *)kmalloc (sizeof (dlist_t));
	tmp->next->size = size;
	if (size)
	{
		tmp->next->item = (void *)kmalloc (size);
		memcpy(tmp->next->item,item,size);
	}
	else
	{
		tmp->next->item = (void *)item;
	}
	tmp->next->next = NULL;
	tmp->next->back = tmp;
	mutex_leave(&mutex);
	//restore_flags (flags);
	return (void *) head;
}

void * push2dList (dlist_t * head, void * item, size_t size)
{
	//uint32 flags;
	//save_flags (flags);
	//cli();
	static mutex_t mutex;
	mutex_enter(&mutex);
	dlist_t * tmp = (dlist_t *)kmalloc (sizeof (dlist_t));
	tmp->size = size;
	if (size)
	{
		tmp->item = (void *)kmalloc (size);
		memcpy(tmp->item,item,size);
	}
	else
	{
		tmp->item = (void *)item;
	}
	tmp->next = head;
	head->back = tmp;
	tmp->back = NULL;
	mutex_leave(&mutex);
	//restore_flags (flags);
	return tmp;
}

void * get_dlist_item (dlist_t * head, size_t number)
{
	dlist_t * tmp = head;
	//uint32 flags;
	//save_flags (flags);
	//cli();
	static mutex_t mutex;
	mutex_enter(&mutex);
	while (0 < (number--) && tmp) tmp = tmp->next;
	mutex_leave(&mutex);
	//restore_flags (flags);
	if (!tmp || !number)
		return (void *) NULL;
	return (void *) tmp->item;
}

void * pop_dlist (dlist_t * head)
{
	dlist_t *tmp = head;
	//uint32 flags;
	//save_flags (flags);
	//cli();
	static mutex_t mutex;
	mutex_enter(&mutex);
	if (!head)
	{
		mutex_leave(&mutex);
		//restore_flags (flags);
		return (void*)NULL;
	}
	head = head->next;
	void * t;
	if (!tmp->size)
		t = tmp->item;
	else
	{
		t = (void *)kmalloc (tmp->size);
		memcpy(t,tmp->item,tmp->size);
		kfree (tmp->item);
	}
	kfree (tmp);
	mutex_leave(&mutex);
	//restore_flags (flags);
	return (void *) t;
}

void * remove_dlist_item (dlist_t * head, size_t number)
{
	dlist_t * tmp = head;
	//uint32 flags;
	//save_flags (flags);
	//cli();
	static mutex_t mutex;
	mutex_enter(&mutex);
	while (0 < (number--) && tmp) tmp = tmp->next;
	if (!tmp || !number)
	{
		mutex_leave(&mutex);
		//restore_flags (flags);
		return (void *)1;
	}
	if (tmp == head)
	{
		head = head->next;
		head->back = NULL;
	}
	else
	{
		tmp->back->next = tmp->next;
		tmp->next->back = tmp->back;
	}
	
	if (tmp->size)
		kfree (tmp->item);		
	kfree (tmp);
	mutex_leave(&mutex);
	//restore_flags (flags);
	return (void *)0;
}

void * remove_dlist (dlist_t * head)
{
	static mutex_t mutex;
	mutex_enter(&mutex);
	while (!remove_list_item (head, (size_t)0));
	mutex_leave(&mutex);
	return (void *) 0;
}
